#include "stdafx.h"
#include "source/Game.h"
//#include <vld.h>

#define WINDOW_TITLE "Demo"

HINSTANCE   g_hApplication;
HWND        g_hWindow;
bool		g_bWindowed = true;
bool		g_bWindowActive = true;
HHOOK		g_hKeyboardHook;


int WINAPI WinMain(HINSTANCE hInstance,			// handle to application
				   HINSTANCE hPrevInstance,		// handle to previous app
				   LPTSTR lpCmdLine,			// command line string
				   int nCmdShow);				// show window value

int WINAPI GameMain(void* lpvArgList);			// handles Game::GetInstance() thread

#if defined(_CONSOLE)
int main(int argc, char* argv[]);				// handles console main
#endif

LRESULT CALLBACK WndProc(HWND hWnd,				// handle to window
						 UINT message,			// incoming message
						 WPARAM wparam,			// message info
						 LPARAM lparam);		// message info

bool InitWindow(void);							// initialize window

void ResizeWindow(HWND hWnd, int width, int height);


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR, int )
{
#if _DEBUG
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	//_CrtSetBreakAlloc(1191);
#endif

	// store application handle
	g_hApplication = hInstance;

	// randomize
	srand(unsigned int(time(0)));

	// init window
	if ( !InitWindow() ) return 0;

	// use to catch windows messages
	MSG msg; ZeroMemory( &msg, sizeof( msg ) );

	// increase precision of windows timer
	//TIMECAPS tc;
	//timeGetDevCaps(&tc, sizeof(TIMECAPS));
	//timeBeginPeriod(tc.wPeriodMin);

	// create the Game::GetInstance() thread
	HANDLE hGameThread = (HANDLE)_beginthreadex(NULL, 0,
		(unsigned int (__stdcall *)(void *))GameMain, 0, 0, NULL);

	// message loop
	while ( msg.message != WM_QUIT )
	{
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{ 
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		Sleep(50);
	}
	
	Game::GetInstance()->m_bRunning = false;

	// wait until game thread terminates
	WaitForSingleObject(hGameThread, INFINITE);
	
	//TerminateThread(hGameThread, 0);

	// destroy the Game::GetInstance() thread
	CloseHandle(hGameThread);
	
	// restore to default
	//timeEndPeriod(tc.wPeriodMin);

	// restore keys
	UnhookWindowsHookEx( g_hKeyboardHook );

	// unregister window
	UnregisterClass("DirectXApplication", g_hApplication);

	// done
	return 0;
}

// Entry point function for the Game::GetInstance()
int WINAPI GameMain(void* lpvArgList)
{
	Game* instance = Game::GetInstance();
	instance->InitGame(g_bWindowed ? false : true, g_hWindow, g_hApplication);

	while(instance->m_bRunning)
	{
		instance->LoopGame();
	}

	instance->EndGame();

	return 0;
}

#if defined(_CONSOLE)
int main(int argc, char* argv[])
{
	WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWDEFAULT);
	
	return 0;
}
#endif

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	// attempt to handle
	switch ( message )
	{
	case WM_SIZE:
		{
			if (wParam == SIZE_MINIMIZED)
				g_bWindowActive = false; // TODO keep a pointer inside the game class to this variable, or just send an event
			else
				g_bWindowActive = true;

		}
		break;
	case WM_ACTIVATEAPP:
		{
			if (wParam == TRUE)
				g_bWindowActive = true;
		}
		break;
	case WM_DESTROY:
		{
			Game::GetInstance()->m_bRunning = false;
			PostQuitMessage( 0 );
		}
		break;
	}

	// pass to default handler
	return DefWindowProc(hWnd, message, wParam, lParam);
}

void ResizeWindow(HWND hWnd, int width, int height)
{  
	// get the size of the current client area
	RECT rcClient;
	GetClientRect(hWnd, &rcClient);

	// get the size of the containing window
	RECT rcWindow;
	GetWindowRect(hWnd, &rcWindow);

	// determine the difference between the two
	POINT diff;
	diff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
	diff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
	// resize the client area
	MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + diff.x, height + diff.y, TRUE);
}

bool InitWindow( void )
{   
	WNDCLASSEX  wndClass;

	// register a new type of window
	ZeroMemory( &wndClass, sizeof( wndClass ) );
	wndClass.cbSize         = sizeof( WNDCLASSEX );             // size of window structure
	wndClass.lpfnWndProc    = ( WNDPROC )WndProc;               // message callback
	wndClass.lpszClassName  = "DirectXApplication";             // class name
	wndClass.hInstance      = g_hApplication;                   // handle to application
	wndClass.hCursor        = LoadCursor( NULL, IDC_ARROW );    // default cursor
	wndClass.hbrBackground  = ( HBRUSH )( COLOR_WINDOWFRAME );  // background brush
	RegisterClassEx( &wndClass );

	// create window of registered type
	g_hWindow = CreateWindow(
		"DirectXApplication", WINDOW_TITLE,                     // class name, window title 
		g_bWindowed ? (WS_OVERLAPPEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME) : ( WS_POPUP | WS_VISIBLE ),   // window style
		CW_USEDEFAULT, CW_USEDEFAULT,                           // x & y coordinates
		SCREEN_WIDTH, SCREEN_HEIGHT,                            // width & height of window
		NULL, NULL,                                             // parent window & menu
		g_hApplication,                                         // handle to application
		NULL );

	// take a guess
	ShowWindow( g_hWindow, SW_SHOW );                           // technically should be nCmdShow
	ResizeWindow(g_hWindow, SCREEN_WIDTH, SCREEN_HEIGHT);
	if (g_bWindowed)
	{
		// Setup the desired client area size
		RECT rWindow;
		rWindow.left	= 0;
		rWindow.top		= 0;
		rWindow.right	= SCREEN_WIDTH;
		rWindow.bottom	= SCREEN_HEIGHT;

		// Get the dimensions of a window that will have a client rect that
		// will really be the resolution we're looking for.

		// Calculate the _width/_height of that window's dimensions
		int windowWidth		= rWindow.right - rWindow.left;
		int windowHeight	= rWindow.bottom - rWindow.top;

		SetWindowPos(g_hWindow, HWND_TOP,	(GetSystemMetrics(SM_CXSCREEN)>>1) - (windowWidth>>1),
			(GetSystemMetrics(SM_CYSCREEN)>>1) - (windowHeight>>1),
			windowWidth, windowHeight, SWP_SHOWWINDOW);
	}
	UpdateWindow( g_hWindow );
	//ShowCursor(FALSE);
	return true;
}